EP15. 모델 특성에 따른 프롬프트
모든 프롬프트는 모델의 SFT(Supervised Fine-Tuning) 학습 구조와 어텐션 토큰 위치 효과에 정렬되어야 의도대로 작동한다.
0. 사전 필수 용어 (선행지식)
본 단원을 이해하기 위해 다음 5개 용어를 먼저 정리합니다. 입문자는 비유와 함께 빠르게 익히세요.
- LLM (Large Language Model) — 텍스트를 입력받아 다음에 올 토큰의 확률 분포를 예측하는 거대 신경망. 비유: "다음 단어 자동완성을 매우 잘하는 기계". 본문 §1~§11 전반에서 가정.
- 토큰 (Token) — 모델이 한 번에 처리하는 텍스트 조각 단위 (한글 1~3 글자, 영어 단어 일부). 비유: "조립 블록 한 개". 본문 §3·§6 어텐션 설명에서 사용.
- 어텐션 (Attention) — 각 토큰이 다른 모든 토큰을 얼마나 참고할지 학습하는 메커니즘. 비유: "회의에서 누구 말을 더 귀담아 들을지 결정". 본문 §6 핵심 원리.
- 파운데이션 모델 (Foundation Model) — 대규모 비지도 사전학습을 거친 1차 모델. SFT 전 단계. 비유: "초중고 일반 교육만 받은 상태". 본문 §1 정의의 전제.
- 컴플리션 (Completion) vs 멀티턴 (Multi-turn) — Completion 은 한 덩어리 문자열에 모든 역할이 합쳐진 형식, Multi-turn 은 역할별 메시지가 배열로 분리된 형식. 비유: "장문 편지 한 통" vs "메신저 대화방". 본문 §3 구조 비교.
📚 참고: 선행지식이 부족하면 AI 엔지니어링 EP0 - 선수지식 또는 HuggingFace LLM Course Chapter 1·2 를 먼저 학습합니다.
💡 실무 노하우: SFT 구조는 모델 카드나
tokenizer.chat_template(HF Transformers) 에 명시되어 있습니다. 새 모델 도입 시 먼저 확인합니다.
1. 주제 정의
모델 특성에 따른 프롬프트 는 LLM 의 SFT 학습 구조(Llama 컴플리션 vs ChatML 멀티턴 vs Responses API 4-role)와 어텐션 토큰 위치 효과에 정렬된 프롬프트 작성 전략입니다.
핵심 아이디어: 신경망은 학습된 데이터를 재연하려는 확률 분포이므로, 프롬프트는 모델의 SFT 학습 데이터 분포와 동일한 형태로 구성해야 합니다.
2. 풀려는 문제
실무 LLM 개발에서 다음 4 가지 문제를 해결합니다.
- 문제 1 — 모델 오작동: Llama 계열의
instruction슬롯에 상세 지침을 잔뜩 넣으면 학습 분포 밖이라 응답 품질이 급락합니다. - 문제 2 — 지침 무시: ChatML 계열의
user메시지에 지침을 두면system보다 영향력이 약해 모델이 지침을 가볍게 처리합니다. - 문제 3 — Few-shot 고착화: few-shot 예시를
system에 넣으면 모델이 예시 답변을 복제하여 일반화 능력이 사라집니다. - 문제 4 — API 레거시 락인: Chat Completions 만 사용하면 GPT 최신 기능(reasoning, MCP, 도구 사용 확장)을 활용할 수 없습니다.
💡 실무 노하우: 위 4 문제는 모두 프롬프트 엔지니어링의 문제가 아니라 SFT 학습 구조에 대한 무지에서 발생합니다. 모델 카드/공식 템플릿을 먼저 읽습니다.
3. 핵심 개념·구조
다음 세 요소가 본 단원의 핵심입니다.
- SFT 학습 구조 (Llama vs ChatML): Llama 계열은
instruction → user → assistant단일 컴플리션, ChatML 계열은system → user → assistant멀티턴. - 어텐션 토큰 위치 효과: 앞 토큰은 후속 토큰에 누적 발산 영향, 뒤 토큰은 다음 토큰 분포에 직접 영향. 원래 강도는 뒤가 더 큼.
- OpenAI Responses API 4-role:
instruction(짧은 역할) +developer(상세 지침) +user+assistant. 내부적으로 instruction+developer 가 합쳐져 system 으로 처리됩니다.
Llama : [INST]<역할>[/INST] <user> => <assistant>
ChatML : system(역할·지침) → user(질의) → assistant(응답)
Resp : instruction(역할) + developer(상세) → user → assistant
flowchart LR
A[프롬프트 입력] --> B{모델 SFT 구조}
B -->|Llama| C[inst 짧게 + user 상세]
B -->|ChatML| D[system 상세 + user 질의 + few-shot 턴]
B -->|Responses| E[instruction 짧게 + developer 상세 + user]
C --> F[정상 응답]
D --> F
E --> F
4. 구현 가이드 (Do It Yourself)
시작 전 (Before you begin)
이 섹션 완료하면 4가지 백엔드(Llama·ChatML·Anthropic·Responses API)에 각각 정렬된 프롬프트를 코드로 작성·검증할 수 있습니다.
선수 조건:
- Python 3.10+
- pip install anthropic openai transformers
- 환경 변수: ANTHROPIC_API_KEY, OPENAI_API_KEY
소요 시간: 약 25분.
Step 1 — Llama 계열 프롬프트 구성
목표: HuggingFace Transformers 의 chat template 으로 Llama 정렬 프롬프트를 생성합니다.
다음 코드를 llama_prompt.py 에 추가합니다.
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B-Instruct")
messages = [
{"role": "system", "content": "너는 학교 선생님이야."},
{"role": "user", "content": "이차방정식의 근의 공식을 알려줘."},
]
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
print(prompt)
이 코드는 Llama 의 공식 chat_template 을 적용해 학습 분포와 동일한 형식의 단일 문자열을 생성합니다.
⚠️ 주의: Llama
instruction슬롯에 상세 지침·제약·입출력 형식을 모두 넣으면 학습한 적 없는 분포라 응답 품질이 급락합니다. 짧은 역할 1~2 문장만 둡니다.💡 실무 노하우: 모델 카드의
chat_template을 직접 읽어 보면 SFT 구조를 그대로 확인할 수 있습니다.📚 참고: HuggingFace Chat Templating 가이드.
✅ 확인: print(prompt) 출력에 <|begin_of_text|> 와 <|start_header_id|>system<|end_header_id|> 토큰이 포함되어 있으면 정상.
Step 2 — ChatML(GPT) 계열 system 메시지 작성
목표: GPT 계열에 권장되는 5 종 내용(역할·지침·실행 방법·제약·입출력 형식)을 system 에 담습니다.
다음 코드를 chatml_prompt.py 에 추가합니다.
from openai import OpenAI
client = OpenAI()
system = """
역할: 한국어 코드 리뷰어.
지침: PEP8, 보안, 가독성 관점에서 평가.
실행 방법: 문제별 우선순위(상/중/하)와 수정 패치 제시.
제약: 추측 금지, 근거를 코드 라인으로 명시.
출력 형식: 마크다운 표 (라인 / 카테고리 / 우선순위 / 패치).
"""
resp = client.chat.completions.create(
model="gpt-5",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": "리뷰: def f(x): return x*2"},
],
)
print(resp.choices[0].message.content)
이 코드는 ChatML 학습이 강한 system 편향을 부여한다는 점을 활용해, 상세 지침을 system 에 집중시킵니다.
⚠️ 주의: 동일한 5 종 내용을
user에 두면 system 보다 영향력이 약해 지침이 부분적으로 무시됩니다.💡 실무 노하우: system 길이가 4K 토큰을 넘으면 모델별 캐시·라우팅 정책이 달라집니다. 프롬프트 캐싱 가격표를 함께 검토합니다.
📚 참고: OpenAI Cookbook Prompt engineering 가이드.
✅ 확인: 응답이 마크다운 표 형식이고 라인 번호 근거를 포함하면 system 지침이 적용된 것.
Step 3 — Few-shot 예시를 user/assistant 턴으로 배치
목표: ChatML 계열에서 few-shot 예시를 system 이 아닌 턴으로 구성합니다.
다음 코드를 few_shot.py 에 추가합니다.
messages = [
{"role": "system", "content": "역할: 영한 번역기. 출력 형식: JSON {ko: ...}"},
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": '{"ko": "안녕"}'},
{"role": "user", "content": "How are you?"},
{"role": "assistant", "content": '{"ko": "잘 지내?"}'},
{"role": "user", "content": "Good morning"},
]
이 구조는 모델의 멀티턴 SFT 학습 분포와 정확히 일치합니다.
⚠️ 주의: 예시를 system 에 두면 모델이 지침으로 인식해 동일 질의에 예시 답변을 그대로 복제할 확률이 매우 높아집니다.
💡 실무 노하우: few-shot 2~5 개가 가장 안정적. 10 개 이상은 토큰 비용 대비 효과 체감이 줄어듭니다.
📚 참고: Anthropic Multishot prompting 가이드.
✅ 확인: 세 번째 user 질의에 대해 예시 패턴({"ko": ...})을 따르되 내용은 다른 답이 나오면 정상 일반화.
Step 4 — OpenAI Responses API 로 전환
목표: 레거시 Chat Completions 를 Responses API 로 옮기고 4-role 을 활용합니다.
다음 코드를 responses_api.py 에 추가합니다.
from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="gpt-5",
input=[
{"role": "developer", "content": "출력 형식: JSON. 추측 금지. 근거 라인 명시."},
{"role": "user", "content": "PEP8 위반 한 줄 예시?"},
],
instructions="너는 코드 리뷰어다.",
)
print(resp.output_text)
instructions 인자에는 짧은 역할·배경만, developer 메시지에는 상세 제약·입출력 구조·절차를 둡니다.
⚠️ 주의:
instruction과developer가 둘 다 system 으로 합쳐지므로, 두 곳에 충돌하는 지시를 두면 동작이 불안정해집니다. 역할은 1곳, 제약은 1곳.💡 실무 노하우: Responses API 는 reasoning effort, 서버측 도구(MCP·웹검색), 스테이트풀 대화 등 신규 기능을 단독 지원합니다.
📚 참고: OpenAI Responses API 마이그레이션 가이드.
✅ 확인: resp.output_text 가 JSON 문자열이고 instructions+developer 의 두 지시가 모두 반영되면 성공.
Step 5 — 동작 확인 (테스트)
import json
# Step 3 결과
assert json.loads(resp.choices[0].message.content)["ko"] # JSON 형식 강제 확인
# Step 4 결과
assert "PEP8" in resp.output_text or "변수" in resp.output_text
print("✅ 모든 백엔드 정렬 OK")
예상 출력:
✅ 모든 백엔드 정렬 OK
5. 적용 사례 (공신력 오픈소스 5+)
다음 오픈소스가 본 단원의 SFT 정렬·멀티 백엔드 추상화 패턴을 실제로 구현하고 있습니다.
- LangChain (
https://github.com/langchain-ai/langchain) —ChatPromptTemplate,ChatOpenAI/ChatAnthropic등 백엔드별 어댑터로 추상화. - LlamaIndex (
https://github.com/run-llama/llama_index) —LLM추상화로 메시지 → 모델별 chat template 변환. - Anthropic Python SDK (
https://github.com/anthropics/anthropic-sdk-python) —client.messages.create의system파라미터 분리, few-shot 은 messages 턴으로. - OpenAI Python SDK (
https://github.com/openai/openai-python) —client.responses.create의instructions/developer롤 분리,client.chat.completions.create레거시 호환. - HuggingFace Transformers (
https://github.com/huggingface/transformers) — 각 모델 토크나이저의chat_templateJinja 로 SFT 구조 그대로 직렬화. - vLLM (
https://github.com/vllm-project/vllm) — OpenAI 호환 서버에서chat_template자동 적용. - Ollama (
https://github.com/ollama/ollama) — ModelfileTEMPLATE디렉티브로 모델별 SFT 형식 보관. - LiteLLM (
https://github.com/BerriAI/litellm) — 100+ 백엔드를 OpenAI Chat Completions 인터페이스로 통일, 내부에서 모델별 변환. - Spring AI (
https://github.com/spring-projects/spring-ai) —SystemMessage/UserMessage/AssistantMessage분리, 모델별 어댑터. - LangChain4j (
https://github.com/langchain4j/langchain4j) — JVM 진영의 동일 추상화.ChatLanguageModel인터페이스.
📚 참고: 위 OSS 들은 모두 GitHub Stars ≥ 5K 또는 Anthropic·OpenAI·Meta·HuggingFace 공식 SDK 입니다.
💡 실무 노하우: LiteLLM 같은 통합 게이트웨이를 쓰면 백엔드 swap 비용이 거의 0 이 되지만, 각 모델의 SFT 특성을 무시한 일률 변환이 되기 쉽습니다. 중요한 프로덕션 경로는 직접 SDK 사용을 권장.
6. 핵심 원리
가장 중요한 원리 두 가지:
- SFT 학습 분포 재연: 신경망은 학습된 데이터 분포의 확률적 재연 장치입니다. 프롬프트가 학습 분포와 다르면 모델은 학습한 적 없는 입력으로 처리하여 품질이 급락합니다.
- 어텐션 위치 누적 효과: 앞 토큰은 모든 후속 토큰 생성에 어텐션을 반복 발산하므로 누적 영향이 크고, 뒤 토큰은 다음 토큰 분포에 직접 영향을 줍니다. 원래 강도는 뒤가 더 크지만, ChatML 의 SFT 학습이 앞쪽 system 편향을 강화해 두 효과가 결합됩니다.
7. 변형·확장
- System 끝 배치 (롱컨텍스트 트릭): 매우 긴 컨텍스트에서 system 영향력이 희석되면 user 마지막에 핵심 제약을 한 번 더 재현합니다.
- Zero-shot 강제 + 외부 검증: few-shot 없이 system 의 출력 형식 명세 + JSON Schema 검증으로 일반화를 유지합니다.
- Async / Streaming: SSE 스트리밍으로 첫 토큰 대기 시간을 단축. UX 와 비용 트레이드오프.
- Batch API: 대량 비동기 작업은 OpenAI Batch / Anthropic Batch 로 50% 비용 절감.
8. 다른 도구·접근과의 비교 (3-way)
- vs LangChain
PromptTemplate— 텍스트 보간 중심. 모델별 SFT 차이를 명시적으로 다루지 않음. ChatPromptTemplate 으로 보완 필요. - vs DSPy 시그니처 기반 — 프롬프트를 함수 시그니처로 추상화. SFT 정렬은 컴파일러가 자동 처리. 메타 추상화 수준에서 한 단계 위.
- vs 직접
chat_template호출 — HuggingFace tokenizer 의 Jinja 템플릿을 직접 적용. 학습 분포와 가장 가깝지만 멀티 백엔드 코드 양 증가.
9. 한계·트레이드오프
- 모델 발전 속도: SFT 학습 방식이 자주 바뀝니다. 가이드는 6 개월 주기로 갱신 필요.
- 추상화 vs 정확성: LiteLLM/LangChain 같은 추상화는 코드 양을 줄이지만 모델별 SFT 정렬을 일률 변환해 품질 손실 가능.
- 롱컨텍스트 희석: 32K+ 컨텍스트에서 system 영향력이 약해지므로 단순 system 배치만으로 충분하지 않음.
- API 마이그레이션 비용: Chat Completions → Responses API 전환 시 라이브러리 호환성과 메시지 스키마 변환 비용이 큽니다.
💡 실무 노하우: Eval 셋(50~200 케이스)으로 마이그레이션 전후 품질 회귀를 측정한 후 전환합니다. promptfoo, OpenAI Evals 등이 도구.
10. 최신 권장 패턴 (2026-05 기준)
- Responses API 우선 — 신규 OpenAI 프로젝트는 Chat Completions 대신 Responses API. MCP·서버측 도구·reasoning effort 단독 지원.
- Structured Output / JSON Schema —
response_format={"type":"json_schema", "schema": ...}로 출력 형식을 모델 수준에서 강제. - Prompt Caching — Anthropic
cache_control, OpenAI 자동 캐시로 동일 system 반복 호출 비용 50~90% 절감. - Extended Thinking / Reasoning — Claude
thinking파라미터, OpenAI reasoning effort 로 복잡 추론 품질 향상. - MCP (Model Context Protocol) — 표준화된 도구·자원 연결 프로토콜. Responses API·Claude Desktop 등이 1차 지원.
11. 메타인지 자기평가
본인 코드·시스템에 적용 가능한지 검증 절차.
Step 1 — 현재 상태 점검
grep -rE "client\.chat\.completions\.create|client\.messages\.create|client\.responses\.create" src/
grep -rE "few.shot|fewshot" prompts/
Step 2 — 적용 가능성 평가
- 사용 중인 백엔드별 SFT 구조를 알고 있는가? (모델 카드 / chat_template 확인 여부)
- system 메시지 길이·내용이 모델별로 차별화되어 있는가?
- few-shot 예시가 system 이 아닌 user/assistant 턴에 있는가?
- OpenAI 호출이 Responses API 호환 가능한가? (LangChain 등 의존성 점검)
Step 3 — 점진 적용
- 모델별 어댑터 함수 1개 작성 (
build_messages(provider, ...)). - Eval 셋 50 케이스로 기존 프롬프트 vs 정렬 프롬프트 품질 측정.
- 핵심 경로 1개부터 마이그레이션, 회귀 모니터링.
- 전사 가이드 문서화 후 점진 확산.
본 학습자료는 SFT 학습 구조·어텐션 위치 효과·OpenAI Responses API 신규 4-role 을 다룹니다. 검증일 2026-05-26, 출처: Anthropic·OpenAI·HuggingFace 공식 문서.
클릭하거나 Space를 눌러 뒤집기